package org.apache.lucene.ocean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;

/**
 * Encapsulates deletes for a transaction
 * 
 */
public class Deletes implements Serializable {
  public static final int DOC_IDS = 1;
  public static final int TERMS = 2;
  private static final long serialVersionUID = 1l;
  /**
   * Terms to delete
   */
  private List<Term> terms = new ArrayList<Term>();
  /**
   * Queries used to delete
   */
  private List<DeleteByQuery> deleteByQueries = new ArrayList<DeleteByQuery>();
  /**
   * The doc ids of the documents deleted by the transaction
   */
  private long[] docIds;

  /**
   * public Deletes(IndexInput input) throws IOException { int docIdsLength =
   * input.readVInt(); if (docIdsLength > 0) { docIds = new long[docIdsLength];
   * for (int x=0; x < docIdsLength; x++) { docIds[x] = input.readVLong(); } }
   * int termsLength = input.readVInt(); for (int x=0; x < termsLength; x++) {
   * String field = input.readString(); String text = input.readString();
   * terms.add(new Term(field, text)); } int dqLength = input.readVInt(); for
   * (int x=0; x < dqLength; x++) { int blen = input.readVInt(); byte[] bytes =
   * new byte[blen]; input.readBytes(bytes, 0, blen);
   * deleteByQueries.add((DeleteByQuery)SerializationUtils.deserialize(bytes)); } }
   */
  public Deletes() {
  }

  /**
   * public void writeTo(IndexOutput output) throws IOException { if (docIds ==
   * null) { output.writeVInt(0); } else { output.writeVInt(docIds.length); for
   * (int x = 0; x < docIds.length; x++) { output.writeVLong(docIds[x]); } }
   * output.writeVInt(terms.size()); for (int x = 0; x < terms.size(); x++) {
   * output.writeString(terms.get(x).field());
   * output.writeString(terms.get(x).text()); }
   * output.writeVInt(deleteByQueries.size()); for (int x = 0; x <
   * deleteByQueries.size(); x++) { byte[] bytes =
   * SerializationUtils.serialize(deleteByQueries.get(x));
   * output.writeVInt(bytes.length); output.writeBytes(bytes, bytes.length); } }
   */
  
  /**
   * Merge deletes
   */
  public void merge(Deletes deletes) {
    terms.addAll(deletes.getTerms());
    deleteByQueries.addAll(deletes.getDeleteByQueries());
  }
  
  /** 
   * If there are doc ids
   */
  public boolean hasDocIds() {
    return docIds != null;
  }

  void setDocIds(long[] docIds) {
    assert this.docIds == null;
    this.docIds = docIds;
  }

  public void addTerm(Term term) {
    terms.add(term);
  }
  
  /**
   * Add a delete by query
   * @param query
   */
  public void addQuery(Query query) {
    deleteByQueries.add(new DeleteByQuery(query));
  }

  public void addDeleteByQuery(DeleteByQuery deleteByQuery) {
    deleteByQueries.add(deleteByQuery);
  }
  
  /**
   * Get the doc ids
   * @return
   */
  public long[] getDocIds() {
    return docIds;
  }
  
  /**
   * If there are deletes
   * @return
   */
  public boolean hasDeletes() {
    if (terms.size() > 0 || deleteByQueries.size() > 0 || docIds != null && docIds.length > 0) {
      return true;
    } else {
      return false;
    }
  }
  
  /**
   * If there are DeleteByQueries
   * @return
   */
  public boolean hasDeleteByQueries() {
    if (deleteByQueries != null && deleteByQueries.size() > 0)
      return true;
    return false;
  }
  
  /**
   * Get the DeleteByQueries
   * @return
   */
  public List<DeleteByQuery> getDeleteByQueries() {
    return deleteByQueries;
  }
  
  /**
   * Wraps a Query for deleting documents
   */
  public static class DeleteByQuery implements Serializable {
    private Query query;

    public DeleteByQuery(Query query) {
      this.query = query;
    }

    public Query getQuery() {
      return query;
    }
  }
  
  /**
   * Get the queries from the DeleteByQueries
   * @return
   */
  public List<Query> getQueries() {
    List<Query> queries = new ArrayList<Query>(deleteByQueries.size());
    for (DeleteByQuery deleteByQuery : deleteByQueries) {
      queries.add(deleteByQuery.getQuery());
    }
    return queries;
  }
  
  /**
   * Get the terms
   * @return
   */
  public List<Term> getTerms() {
    return terms;
  }
  
  /**
   * If there are term deletes
   * @return
   */
  public boolean hasTerms() {
    if (terms != null && terms.size() > 0)
      return true;
    return false;
  }
}
